package org.javarosa.mesh4j.sync.adapter;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.Vector;

import org.javarosa.core.JavaRosaServiceProvider;
import org.javarosa.core.model.FormDef;
import org.javarosa.core.model.storage.FormDefMetaData;
import org.javarosa.core.model.storage.FormDefRMSUtility;
import org.javarosa.core.services.storage.utilities.IRecordStoreEnumeration;
import org.javarosa.xform.mesh4j.extensions.FormDefUtils;
import org.mesh4j.sync.adapters.rms.storage.RmsRecordContent;
import org.mesh4j.sync.adapters.rms.storage.RmsStorageSyncIDRmsRecordRelation;
import org.mesh4j.sync.adapters.split.IContentAdapter;
import org.mesh4j.sync.adapters.split.ISyncEntityRelationListener;
import org.mesh4j.sync.model.IContent;
import org.mesh4j.sync.validations.MeshException;

public class FormDefContentAdapter implements IContentAdapter, ISyncEntityRelationListener {

	private static final String FORM_DEF_SYNC_ID_REL = "M4X_FORM_DEF_SYNC_ID_REL";

	private final static String XML_HEADER = "<?xml version='1.0' ?>";
	
	// MODEL VARIABLES
	private RmsStorageSyncIDRmsRecordRelation rmsStorageSyncIDRmsRecordRelation;
	private String formName;
	
	// BUSINESS METHODS
	public FormDefContentAdapter() {
		this.rmsStorageSyncIDRmsRecordRelation = new RmsStorageSyncIDRmsRecordRelation(FORM_DEF_SYNC_ID_REL);
		this.formName = "FormDef";
	}

	public void delete(IContent entity) {
		try{
			int instanceID = this.getAssociationRMS().getInstanceID(entity.getId());
			FormDefRMSUtility modelUtil = this.getFormDefRMSUtility();
			modelUtil.deleteRecord(instanceID);
			this.getAssociationRMS().deleteAssociation(entity.getId());
		} catch (Exception e) {
			e.printStackTrace();
			throw new MeshException(e.getMessage());
		}
	}

	public IContent get(String syncId) {
		try {
			int instanceID = this.getAssociationRMS().getInstanceID(syncId);
			if(instanceID == -1){
				return null;
			}
			
			FormDefRMSUtility modelUtil = this.getFormDefRMSUtility();

			FormDef formDef = new FormDef();
			modelUtil.retrieveFromRMS(instanceID, formDef);

			String xml = serializeModel(formDef);

			return new RmsRecordContent(xml, syncId, instanceID, formDef.getTitle());
		} catch (Exception e) {
			e.printStackTrace();
			throw new MeshException(e.getMessage());
		}
	}

	public Vector<IContent> getAll(Date since) {
		Vector<IContent> result = new Vector<IContent>();
		FormDefRMSUtility modelUtil = this.getFormDefRMSUtility();
		IRecordStoreEnumeration records = null;
		try{
			records = modelUtil.enumerateMetaData();
			int instanceId = -1;
			FormDef formDef = null;
			FormDefMetaData metaData = null;
			while (records.hasNextElement()) {
				metaData = new FormDefMetaData();
				modelUtil.retrieveMetaDataFromRMS(records.nextRecordId(), metaData);
			
				formDef = new FormDef();
				instanceId = metaData.getRecordId();
				modelUtil.retrieveFromRMS(instanceId, formDef);
					
				String xml = serializeModel(formDef);
									
				String syncID = this.getAssociationRMS().getSyncID(instanceId);		// Can be null
				result.addElement(new RmsRecordContent(xml, syncID, instanceId, formDef.getTitle()));
			}
		} catch (Exception e) {
			e.printStackTrace();
			throw new MeshException(e.getMessage());
		}finally{
			if(records != null){
				records.destroy();
			}
		}
		return result;
	}

	public String getType() {
		return this.formName;
	}

	public IContent normalize(IContent content) {
		try{
			int recordId = this.getAssociationRMS().getInstanceID(content.getId());
			return new RmsRecordContent(content.getPayload(), content.getId(), recordId, this.getType());
		} catch (Exception e) {
			e.printStackTrace();
			throw new MeshException(e.getMessage());
		}
	}

	public void save(IContent entity) {

		try {
			int instanceID = this.getAssociationRMS().getInstanceID(entity.getId());

			FormDefRMSUtility utility = this.getFormDefRMSUtility();
			FormDef formDef = this.deserializeModel(entity.getPayload());

			if (instanceID == -1) {
				instanceID = utility.writeToRMS(formDef);
				this.getAssociationRMS().addAssociation(entity.getId(), instanceID);
			} else {
				utility.updateToRMS(instanceID, formDef);
			}
		} catch (Exception e) {
			e.printStackTrace();
			throw new MeshException(e.getMessage());
		}
	}

	private String serializeModel(FormDef formDef) throws IOException, UnsupportedEncodingException {
		return "";		// TODO (JMT) Serialize formDef
	}
	
	private FormDef deserializeModel(String payload){
		FormDef formDef = FormDefUtils.getFormDefFromXml(XML_HEADER+payload);
		return formDef;
	}
	
	public void notifyNewSyncForContent(String syncId, IContent content) {
		RmsRecordContent dataModelTreeContent = (RmsRecordContent) content;
		dataModelTreeContent.setSyncId(syncId);
		if(dataModelTreeContent.getRecordId() != -1){
			try{
				this.getAssociationRMS().addAssociation(syncId, dataModelTreeContent.getRecordId());
			} catch (Exception e) {
				e.printStackTrace();
				throw new MeshException(e.getMessage());
			}
		}		
	}
	
	private FormDefRMSUtility getFormDefRMSUtility() {
		return (FormDefRMSUtility) JavaRosaServiceProvider.instance()
				.getStorageManager().getRMSStorageProvider().getUtility(
						FormDefRMSUtility.getUtilityName());
	}

	private RmsStorageSyncIDRmsRecordRelation getAssociationRMS() {
		return rmsStorageSyncIDRmsRecordRelation;
	}

	public void notifyRemoveSync(String syncId) {
		try{
			this.getAssociationRMS().deleteAssociation(syncId);
		} catch (Exception e) {
			e.printStackTrace();
			throw new MeshException(e.getMessage());
		}
	}

	public void deleteRecordStorage(boolean deleteXFroms) {
		this.getAssociationRMS().deleteRecordStorage();
		if(deleteXFroms){
			this.getFormDefRMSUtility().tempEmpty();
		}
	}

	public void deleteAll() {
		FormDefRMSUtility modelUtil = this.getFormDefRMSUtility();
		modelUtil.tempEmpty();
	}

}
